#import "RNDetailHeader.h"
#import "RNConstants.h"


@interface RNDetailHeader (RNDetailHeaderPrivateMethods)
-(void)bindControllers_;
@end

@implementation RNDetailHeader

@synthesize displayIndex = displayIndex_;
@synthesize rootObject = rootObject_;
@synthesize titleTemplate = titleTemplate_;
@synthesize keyPath = keyPath_;
@synthesize showsTitle = showsTitle_;
@synthesize predicate = predicate_;
@synthesize primaryController = primaryController_;
@synthesize intermediateController = intermediateController_;

@synthesize showsChildren = showsChildren_;
@synthesize expandsChildren = expandsChildren_;
@synthesize headerHeight = headerHeight_;

+(NSArray *)arrayOfHeadersWithRootObject:(id)rootObject filteredWithObject:(id)filterObject inManagedObjectContext:(NSManagedObjectContext *)moc {
    NSMutableString *rootObjectName = [rootObject isKindOfClass:[NSManagedObject class]] ? [[[rootObject entity] name] mutableCopy] : [[rootObject className] mutableCopy];
    Class headerClass = NSClassFromString([NSString stringWithFormat:@"%@DetailHeader", rootObjectName]);
    if (![headerClass respondsToSelector:@selector(arrayOfHeadersWithRootObject:filteredWithObject:inManagedObjectContext:)])
        return nil;
    return [headerClass arrayOfHeadersWithRootObject:rootObject filteredWithObject:filterObject inManagedObjectContext:(NSManagedObjectContext *)moc];
}

-(id)init {
	[NSException raise:@"RNDetailHeaderException" format:@"An instance of an RNDetailHeader was initialized using init vice initWithController:"];
    return nil;
}

-(id)initWithRootObject:(id)rootObject  {
    if (!(self = [super init]))
        return nil;
    
    [self setRootObject:rootObject];
    [self setDisplayIndex:0];
    [self setPrimaryController:[[NSArrayController alloc] initWithContent:nil]];
    [[self primaryController] setAutomaticallyRearrangesObjects:YES];
    [self setIntermediateController:[[NSArrayController alloc] initWithContent:nil]];
    [[self primaryController] addObserver:self forKeyPath:@"arrangedObjects" options:NSKeyValueObservingOptionNew context:NULL];
    [self setShowsChildren:YES];

    return self;
}

- (id)copyWithZone:(NSZone *)zone {
    RNDetailHeader *copy = [[RNDetailHeader alloc] initWithRootObject:[self rootObject]];
    [copy setDisplayIndex:[self displayIndex]];
    [copy setTitleTemplate:[self titleTemplate]];
    [copy setShowsTitle:[self showsTitle]];
    [copy setShowsChildren:[self showsChildren]];
    [copy setExpandsChildren:[self expandsChildren]];
    return copy;
    // Doesn't copy rootObject, predicate, or children properties
}

-(void)setKeyPath:(NSString *)keyPath {
    keyPath_ = [keyPath copy];
    if (![self rootObject])
        return;
    [self bindControllers_];
}

+(NSSet *)keyPathsForValuesAffectingChildren {
    return [NSSet setWithObjects:@"showsChildren", nil];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    NSUInteger objectCount = [[[self primaryController] arrangedObjects] count];
    if (objectCount == 0) 
        [self setShowsTitle:NO];
    else if (objectCount > 0 && [self titleTemplate])
        [self setShowsTitle:YES];
    // Only observing primaryController.arrangedObjects.  This is a hack because NSArrayController's arrangedObjects won't let you use +keyPathsForValuesAffecting...
    [self willChangeValueForKey:@"children"];
    [self didChangeValueForKey:@"children"];
}

-(NSArray *)children {
    if (![self showsChildren])
        return nil;
    NSArray *children = [[self primaryController] arrangedObjects];
    return children;
}

-(NSDictionary *)objectDictionary {
    if (![self showsTitle])
        return nil;
    return [NSDictionary dictionaryWithObject:[self title] forKey:RNTitleKey];
}

-(NSUInteger)childCount {
    return [[[self primaryController] arrangedObjects] count];
}

+(NSSet *)keyPathsForValuesAffectingObjectDictionary {
    return [NSSet setWithObjects:@"showsTitle", @"titleTemplate", nil];
}

-(NSString *)title {
    if (![self showsTitle])
        return nil; 
    NSString *title = [NSString stringWithFormat:@"%@ %i %@ %@", ([self showsChildren] ? @"Hide" : @"Show"), [self childCount], ([self childCount] == 1 ? @"item" : @"items"),  [self titleTemplate]];
    return title;
}


#pragma mark -
#pragma mark Private methods

-(void)bindControllers_ {
    NSAssert([[self keyPath] length] > 0, @"RNDetailHeader:bindControllers_: initialized with nil or empty keyPath");
    NSArray *keyComponents = [[self keyPath] componentsSeparatedByString:@"."];
    if ([keyComponents count] == 1) {
        [[self primaryController] bind:NSContentSetBinding toObject:[self rootObject] withKeyPath:[self keyPath] options:nil];
        return;
    }
    // If more than one component, build a keypath that strips the first component
    NSMutableString *intermediateKeyPath = [NSMutableString stringWithString:@"arrangedObjects."];
    NSMutableString *intermediateComponents = [[self keyPath] mutableCopy];
    [intermediateComponents deleteCharactersInRange:NSMakeRange(0, [[keyComponents objectAtIndex:0] length] + 1)];
    [intermediateKeyPath appendString:intermediateComponents];
    [[self intermediateController] bind:NSContentSetBinding toObject:[self rootObject] withKeyPath:[keyComponents objectAtIndex:0] options:nil];
    [[self primaryController] bind:NSContentArrayBinding toObject:[self intermediateController] withKeyPath:intermediateKeyPath options:nil];
}

@end
